﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BFlatCompile.Nodes
{
	public class IfStatement : Executable
	{
		public Expression Condition { get; private set; }
		public Executable[] TrueCode { get; private set; }
		public Executable[] FalseCode { get; private set; }
		public Token OpenParenToken { get; private set; }

		private IfStatement(Expression condition, Executable[] trueCode, Executable[] falseCode, Token openParenToken)
		{
			this.Condition = condition;
			this.TrueCode = trueCode;
			this.FalseCode = falseCode;
			this.OpenParenToken = openParenToken;
		}

		public Executable CreateSimpleIf(Expression condition, Executable singleTrueStatement, Token openParenToken)
		{
			return new IfStatement(condition, new Executable[] { singleTrueStatement }, new Executable[0], openParenToken);
		}

		public static Executable ParseIf(Tokens tokens)
		{
			tokens.PopExpected("if");
			tokens.PopExpected("(");
			Token token = tokens.PreviousToken();
			Expression trueCondition = Expression.Parse(tokens);
			tokens.PopExpected(")");
			Executable[] trueCode = CodeBlock.Parse(tokens, false);
			Executable[] falseCode = new Executable[0];
			if (tokens.PopIfPresent("else"))
			{
				falseCode = CodeBlock.Parse(tokens, false);
			}

			// OPTIMIZING: if (!X) { Y } else { Z } ---> if(X) { Z } else { Y }
			while (falseCode.Length > 0 && trueCondition is BooleanNot)
			{
				// TODO: make sure the convention of !!value has no usefulness
				trueCondition = ((BooleanNot)trueCondition).Expression;
				Executable[] t = trueCode;
				trueCode = falseCode;
				falseCode = t;
			}

			return new IfStatement(trueCondition, trueCode, falseCode, token);
		}

		public override void ResolveCode(Class c, Dictionary<object, object> parents)
		{
			foreach (Executable[] code in new Executable[][] { this.TrueCode, this.FalseCode })
			{
				if (code != null)
				{
					foreach (Executable exec in code)
					{
						exec.ResolveCode(c, parents);
					}
				}
			}

			this.Condition.ResolveCode(c, parents);
		}

		public override void ResolveClassToThis(Class c)
		{
			foreach (ICodeContainer item in new Consolidator()
				.Add(this.Condition)
				.Add(this.TrueCode)
				.Add(this.FalseCode).List())
			{
				item.ResolveClassToThis(c);
			}
		}
	}
}
